

<!DOCTYPE html>
<html lang="zh" data-default-color-scheme=&#34;auto&#34;>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/walker_sue/img/favicon.png">
  <link rel="icon" type="image/png" href="/walker_sue/img/favicon.png">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="">
  <meta name="author" content="lk">
  <meta name="keywords" content="">
  <title>CTR预估与Youtube推荐系统 - Walker_Sue</title>

  <link  rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.staticfile.org/github-markdown-css/4.0.0/github-markdown.min.css" />
  <link  rel="stylesheet" href="/walker_sue/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/10.0.0/styles/github-gist.min.css" />
    
  

  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/walker_sue/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script  src="/walker_sue/js/utils.js" ></script>
  <script  src="/walker_sue/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.3.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/walker_sue/">&nbsp;<strong>Walker</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/walker_sue/">
                <i class="iconfont icon-home-fill"></i>
                主页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/walker_sue/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/walker_sue/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/walker_sue/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/walker_sue/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item dropdown">
              <a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                <i class="iconfont icon-books"></i>
                文档
              </a>
              <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/">
                    
                    主题博客
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/docs/guide/">
                    
                    配置指南
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/docs/icon/">
                    
                    图标用法
                  </a>
                
              </div>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;</a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" href="javascript:">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner intro-2" id="background" parallax=true
         style="background: url('/walker_sue/img/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="container page-header text-center fade-in-up">
    <span class="h2" id="subtitle">
    
</span>




<div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2021-07-31 18:43" pubdate>
        July 31, 2021 pm
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      6.3k 字
    </span>
  

  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      67
       分钟
    </span>
  

  
  
</div>


</div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid">
  <div class="row">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-md">
      <div class="container nopadding-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto" id="post">
            <!-- SEO header -->
            <h1 style="display: none">CTR预估与Youtube推荐系统</h1>
            
            <div class="markdown-body" id="post-body">
              <div align='center' ><font size='10'>机器学习-BI</font></div>


<hr>
<div align='center' ><font size='5'>Week_21</font></div>
<div align='center' ><font size='5'>CTR预估与Youtube推荐系统</font></div>

<hr>
<h2 id="1-CTR推荐算法"><a href="#1-CTR推荐算法" class="headerlink" title="1.CTR推荐算法"></a>1.CTR推荐算法</h2><h3 id="CTR架构"><a href="#CTR架构" class="headerlink" title="CTR架构"></a><strong>CTR架构</strong></h3><p>一个典型的CTR流程如下图所示：</p>
<p><img src="https://pic3.zhimg.com/v2-e231cc828e68113f4226b9fb59fbaa8a_b.jpg" srcset="/walker_sue/img/loading.gif"></p>
<p>如上图，主要包括两大部分：离线部分、在线部分，其中离线部分目标主要是训练出可用模型，而在线部分则考虑模型上线后，性能可能随时间而出现下降，弱出现这种情况，可选择使用Online-Learning来在线更新模型：</p>
<ul>
<li><p>离线部分：</p>
<ul>
<li>数据收集：主要收集和业务相关的数据，通常会有专门的同事在app位置进行埋点，拿到业务数据；</li>
<li>预处理：对埋点拿到的业务数据进行去脏去重；</li>
<li>构造数据集：经过预处理的业务数据，构造数据集，在切分训练、测试、验证集时应该合理根据业务逻辑来进行切分；</li>
<li>特征工程：对原始数据进行基本的特征处理，包括去除相关性大的特征，离散变量one-hot，连续特征离散化等等;</li>
<li>模型选择：选择合理的机器学习模型来完成相应工作，原则是先从简入深，先找到baseline，然后逐步优化；</li>
<li>超参选择：利用gridsearch、randomsearch或者hyperopt来进行超参选择，选择在离线数据集中性能最好的超参组合；</li>
<li>在线A/B Test：选择优化过后的模型和原先模型（如baseline）进行A/B Test，若性能有提升则替换原先模型；</li>
</ul>
</li>
<li><p>在线部分</p>
<ul>
<li>Cache &amp; Logic：设定简单过滤规则，过滤异常数据；</li>
<li>模型更新：当Cache &amp; Logic 收集到合适大小数据时，对模型进行pretrain+finetuning，若在测试集上比原始模型性能高，则更新model </li>
</ul>
</li>
<li><p>server的模型参数；</p>
<ul>
<li>Model Server：接受数据请求，返回预测结果；</li>
</ul>
</li>
</ul>
<h3 id="Logistic-Regression"><a href="#Logistic-Regression" class="headerlink" title="Logistic Regression"></a><strong>Logistic Regression</strong></h3><p>最简单的模型也应该是工业界应用最广的方法，Logistic<br>Regression算法简单易于调参，属于线性模型，原理如下图：</p>
<p><img src="lr.png" srcset="/walker_sue/img/loading.gif"></p>
<p>将CTR模型建模为一个分类问题，利用LR预测用户点击的概率； 通常我们只需要离线收集好数据样本构造数据集，选择好合适的特征空间，离线训练好模型，测试在离线数据集上的性能之后，即可上线，也可以适应数据分布随时间突变严重的情况，采用online-learning的策略来对模型进行相对频繁的更新，模型的简单能够保证这部分的需求能够得到保障。</p>
<h3 id="PLOY2"><a href="#PLOY2" class="headerlink" title="PLOY2"></a><strong>PLOY2</strong></h3><p>LR优点是简单高效，缺点也很明显，它太简单，视特征空间内特征之间彼此独立，没有任何交叉或者组合关系，这与实际不符合，比如在预测是否会点击某件t恤是否会点击，如果在夏天可能大部分地区的用户都会点击，但是综合季节比如在秋天，北方城市可能完全不需要，所以这是从数据特征维度不同特征之间才能体现出来的。因此，必须复杂到能够建模非线性关系才能够比较准确地建模复杂的内在关系，而PLOY2就是通过特征的二项式组合来建模这类特征的复杂的内在关系,二项式部分如下图公式：</p>
<p><img src="ploy2.png" srcset="/walker_sue/img/loading.gif"></p>
<p>然而理想是美好的，现实却是残酷的，PLOY2有一个明显的问题，就是在实际场景中，大部分特征都是稀疏的，即大部分特征值为0，对这些稀疏的特征做二项式组合，会发现最后大部分特征值都是0，而在梯度更新时，当大部分feature为0时，其实梯度并不更新，所以PLOY2的方法在实际场景中并不能比较好地解决这类特征组合来建模更复杂线性关系的问题。</p>
<h3 id="Factorization-Machine"><a href="#Factorization-Machine" class="headerlink" title="Factorization Machine"></a><strong>Factorization Machine</strong></h3><p>上面PLOY2虽然理论上能够建模二项式关系，但是在实际场景下稀疏数据时，无法使用，而FM就是为了解决这里PLOY2的短板的，FM的基本原理是将这些二项式矩阵做矩阵分解，将高维稀疏的特征向量映射到低维连续向量空间，然后根据内积表示二项式特征关系：=</p>
<p><img src="ploy2_a.jpg" srcset="/walker_sue/img/loading.gif"><br><img src="ploy2_b.png" srcset="/walker_sue/img/loading.gif"></p>
<p>复杂度为$O(kn^2)$，作者提出了一种简化的算法：</p>
<p><img src="fm.png" srcset="/walker_sue/img/loading.gif"></p>
<p>将复杂度简化为$O(kn)$ 然后就是SGD来更新模型参数，使模型收敛（这里还有很多其他替代SGD的方法，在FFM中有提到）：</p>
<p><img src="fm2.png" srcset="/walker_sue/img/loading.gif"></p>
<p>训练时间复杂度也是$O(kn)$，也就是线性时间，FM通过对二项式稀疏进行低维连续空间的转换，能够有效地解决PLOY2中存在的二次项系数在大规模系数数据下不更新的问题，另外由于训练预测复杂度均为线性，PLOY2+SVM这样逻辑下由于要计算多项式核，复杂度是n^2，由于FM的这几个特征，在实际场景中，FM也大规模的应用在CTR中，尤其是在数据极其系数的场景下，FM效果相对于其他算法有很明星的改善。</p>
<h3 id="Field-aware-FM"><a href="#Field-aware-FM" class="headerlink" title="Field-aware FM"></a><strong>Field-aware FM</strong></h3><p>FFM全程是 Field-aware<br>FactorizationMachine，相对于FM增加了Field信息，每个特征属于一个field，举个例子：</p>
<p><img src="ffm.png" srcset="/walker_sue/img/loading.gif"></p>
<p>而相对于FM，只有Feature_index相同个数的低维连续表示，而FFM则不同，每一个feature对不同的field有不同的表示，所以有#Field_index*#Feature_index个不同的表示：</p>
<p><img src="ffm2.png" srcset="/walker_sue/img/loading.gif"></p>
<p>通常由于每个低维隐变量表示只学习特定field的表示，所以FFM的隐变量长度相对于FM的隐变量维度要小的多。FFM的优化问题相对其比较简单，可以看看FFM这篇paper，里面比较详细地描述优化过程，还有相关的伪代码 <a href="https://link.zhihu.com/?target=https://www.andrew.cmu.edu/user/yongzhua/conferences/ffm.pdf">https://www.andrew.cmu.edu/user/yongzhua/conferences/ffm.pdf</a>。</p>
<h3 id="FNN"><a href="#FNN" class="headerlink" title="FNN"></a><strong>FNN</strong></h3><p>从12年在ImageNet上深度学习超过经典模型之后，在计算机视觉、语音、NLP都有很多相关的工作，而在CTR上，深度学习的建模能力也有一些应用，FNN和SNN就是其中的一些尝试，来源于<a href="https://link.zhihu.com/?target=https://arxiv.org/pdf/1601.02376.pdf">DeepLearning over Multi-field Categorical Data – A Case Study on User ResponsePrediction</a>，这里稍微描述下相关的做法：</p>
<p><img src="fnn.png" srcset="/walker_sue/img/loading.gif"></p>
<p>网络底层由FM来进行参数初始化，W的元素由FM中的低维连续空间向量表示来做初始化：</p>
<p><img src="fnn2.png" srcset="/walker_sue/img/loading.gif"></p>
<p>而构成W的低维连续空间向量表示预先由FM在数据集 上生成，模型在训练过程中，会通过BP来更新FM层参数，其他步骤和常见的MLP没有什么区别，这里重点就是底层如何介入FM层参数的问题；</p>
<h3 id="CCPM"><a href="#CCPM" class="headerlink" title="CCPM"></a><strong>CCPM</strong></h3><p>CCPM利用卷积网络来做点击率预测：</p>
<p><img src="ccpm.png" srcset="/walker_sue/img/loading.gif"></p>
<h3 id="PNN"><a href="#PNN" class="headerlink" title="PNN"></a><strong>PNN</strong></h3><p>PNN主要是在深度学习网络中增加了一个inner/outer<br>product layer，用来建模特征之前的关系，如下图，Product layer部分Z是weight*feature，P部分weight*I(feature_i,feature_j)用来建模二项式关系：</p>
<p><img src="pnn.png" srcset="/walker_sue/img/loading.gif"></p>
<p>PNN按product层的功能分为inner product<br>layer和outer product layer，区别如下：</p>
<p><img src="pnn2.png" srcset="/walker_sue/img/loading.gif"></p>
<p>和FM类似，构造好网络之后，对输入数据做embedding处理之后得到低维的连续向量表示，经过任意两个feature的进行inner product or<br>outer product（1也为feature的一部分，所以可以建模线性关系），这里很容易发现，这部分特征大小会变大很多（二次项数量级）,尤其是稀疏空间，和PLOY2遇到的问题类似，变得很难训练，受FM启发，可以把这个大矩阵转换矩阵分解为小矩阵和它的转置相乘，表征到低维度连续向量空间，来减少模型复杂度：</p>
<p><img src="pnn3.png" srcset="/walker_sue/img/loading.gif"></p>
<h3 id="DeepFM"><a href="#DeepFM" class="headerlink" title="DeepFM"></a><strong>DeepFM</strong></h3><p>DeepFM更有意思的地方是WDL和FM结合了，其实就是把PNN和WDL结合了，PNN即将FM用神经网络的方式构造了一遍，作为wide的补充，原始的Wide and Deep，Wide的部分只是LR，构造线性关系，Deep部分建模更高阶的关系，所以在Wide and Deep中还需要做一些特征的东西，如Cross Column的工作，而我们知道FM是可以建模二阶关系达到Cross column的效果，DeepFM就是把FM和NN结合，无需再对特征做诸如Cross Column的工作了，这个是我感觉最吸引人的地方，其实FM的部分感觉就是PNN的一次描述，这里只描述下结构图，PNN的部分前面都描述, FM部分：</p>
<p><img src="deepfnn.png" srcset="/walker_sue/img/loading.gif"></p>
<p>Deep部分：</p>
<p><img src="deepfnn2.png" srcset="/walker_sue/img/loading.gif"></p>
<p>DeepFM相对于FNN、PNN，能够利用其Deep部分建模更高阶信息（二阶以上），而相对于Wide and Deep能够减少特征工程的部分工作，wide部分类似FM建模一、二阶特征间关系， 算是NN和FM的一个更完美的结合方向，另外不同的是如下图，DeepFM的wide和deep部分共享embedding向量空间，wide和deep均可以更新embedding部分，虽说wide部分纯是PNN的工作，但感觉还是蛮有意思的。</p>
<p><img src="deepfnn3.png" srcset="/walker_sue/img/loading.gif"></p>
<h3 id="Wide-amp-Deep"><a href="#Wide-amp-Deep" class="headerlink" title="Wide&amp;Deep"></a><strong>Wide&amp;Deep</strong></h3><p><img src="wide.png" srcset="/walker_sue/img/loading.gif"><br><img src="deep.png" srcset="/walker_sue/img/loading.gif"><br><img src="wide_deep.png" srcset="/walker_sue/img/loading.gif"></p>
<h3 id="其他的一些方法"><a href="#其他的一些方法" class="headerlink" title="其他的一些方法"></a><strong>其他的一些方法</strong></h3><ul>
<li>GBDT+LR：Facebook提出利用GBDT探索海量特征空间的特征组合，减少特征工程工作量，性能很好；</li>
<li>MLR：阿里妈妈前端时间提出的一种增强LR模型，将region的划分考虑进去来建模非线性关系，感觉类似于深度学习的Attention机制，据说在阿里妈妈相关业务提升很多；</li>
</ul>
<h2 id="2-YouTube推荐系统"><a href="#2-YouTube推荐系统" class="headerlink" title="2.YouTube推荐系统"></a>2.YouTube推荐系统</h2><ol>
<li>召回阶段的DNN模型</li>
<li>主要特征处理</li>
<li>样本年龄</li>
<li>样本和上下文选择</li>
<li>不对称的共同浏览问题</li>
<li>负采样</li>
<li>不同网络深度和特征的实验</li>
<li>排序阶段的建模</li>
<li>排序阶段的特征工程（分类特征、连续特征）</li>
<li>隐藏层的实验</li>
</ol>
<h3 id="召回阶段的DNN模型："><a href="#召回阶段的DNN模型：" class="headerlink" title="召回阶段的DNN模型："></a>召回阶段的DNN模型：</h3><p><img src="01.png" srcset="/walker_sue/img/loading.gif"></p>
<ul>
<li>把推荐问题看成一个“超大规模多分类”问题</li>
</ul>
<blockquote>
<p>即在时刻t，为用户U（上下文信息C）在视频库V中精准的预测出视频i的类别（每个具体的视频视为一个类别，i即为一个类别）：</p>
</blockquote>
<p><img src="02.png" srcset="/walker_sue/img/loading.gif"></p>
<p>U为用户-上下文的高维embedding。向量vj每个候选视频的embedding向量</p>
<blockquote>
<p>DNN的任务就是在用户信息，上下文信息为输入条件的情况下，学习用户的embedding向量u，通过一个softmax分类器，u能够有效的从视频语料库中识别视频的类别（也就是推荐的结果）<br>由于数据稀疏性问题，训练数据的正负样本选取采用用户隐式反馈数据，即完成了观看的事件作为样本。<br>比如训练数据为(u1,c1,5) =&gt; 用户u1在上下文c1的情况下观看了类别为5的视频</p>
</blockquote>
<ul>
<li>使用DNN的一个关键优点是，DNN的输入可以方便的处理离散和连续变量</li>
<li>输入是用户浏览历史、搜索历史、人口统计学信息和其余上下文信息concat生成的输入向量</li>
<li>模型架构中间是三个隐层的DNN结构</li>
<li>输出分线上和离线训练两个部分。</li>
<li>将用户观看历史和搜索历史通过embedding的方式映射成为一个稠密的向量，同时用户场景信息以及用户画像信息（比如年龄，性别等离散特征）也被归一化到[0,1]作为DNN的输入</li>
</ul>
<p><img src="03.png" srcset="/walker_sue/img/loading.gif"></p>
<p>ANN算法处，不必然采用LSH算法</p>
<blockquote>
<p>离线训练阶段输出层为softmax层，服务阶段直接用user Embedding和video Embedding计算dot-product表示分数，取topk作为候选结果。<br>最重要问题是在性能，因此使用类似局部敏感哈希LSH（近似最近邻方法）</p>
</blockquote>
<h3 id="主要特征的处理"><a href="#主要特征的处理" class="headerlink" title="主要特征的处理"></a>主要特征的处理</h3><ul>
<li>embedded video watches =&gt; watch vector</li>
</ul>
<blockquote>
<p>用户的历史观看是一个稀疏的，变长的视频id序列，采用类似于word2vec的做法，每个视频都会被embedding到固定维度的向量中。最终通过加权平均（可根据重要性和时间进行加权）得到固定维度的watch vector</p>
</blockquote>
<ul>
<li>embedded search tokens =&gt; Search vector</li>
</ul>
<blockquote>
<p>和watch vector生成方式类似</p>
</blockquote>
<ul>
<li>用户画像特征</li>
</ul>
<blockquote>
<p>如地理位置，设备，性别，年龄，登录状态等连续或离散特征都被归一化为[0,1]</p>
</blockquote>
<ul>
<li>用户画像特征和watch vector以及search vector做拼接（concatenate）</li>
</ul>
<p><img src="04.png" srcset="/walker_sue/img/loading.gif"></p>
<blockquote>
<p>把历史搜索query分词后token的embedding向量加权平均，反映用户的整体搜索历史</p>
</blockquote>
<h3 id="推荐系统中的example-age（样本年龄）"><a href="#推荐系统中的example-age（样本年龄）" class="headerlink" title="推荐系统中的example age（样本年龄）"></a>推荐系统中的example age（样本年龄）</h3><ul>
<li>用户更倾向于推荐尽管相关度不高但是新鲜fresh的视频。</li>
<li>Example age特征表示视频被上传之后的时间。</li>
<li>每一秒中，YouTube都有大量视频被上传，推荐这些最新视频对于YouTube来说是极其重要的。</li>
<li>推荐系统往往是利用用户过去的行为来预测未来，那么对于历史行为，推荐系统通常是能够学习到一种隐式的基准的。但是对于视频的流行度分布，往往是高度不稳定的。</li>
<li>将example age作为一个特征拼接到DNN的输入向量。训练时，时间窗口越靠后，该值越接近于0或者为一个小负数。加入了example age特征后，模型效果和观测到的实际数据更加逼近</li>
</ul>
<p><img src="05.png" srcset="/walker_sue/img/loading.gif"></p>
<h3 id="正负样本和上下文选择"><a href="#正负样本和上下文选择" class="headerlink" title="正负样本和上下文选择"></a>正负样本和上下文选择</h3><ul>
<li>在有监督学习问题中，label选择非常关键，因为label决定了你做什么，决定了你的上限，而feature和model都是在逼近label。</li>
<li><strong>使用更广泛的数据源，</strong>训练样本要用youtube上的所有视频观看记录，而不只是系统推荐的视频观看记录。否则，面对新视频的时候很难推荐，并且推荐器会过度偏向exploitation</li>
<li><strong>为每个用户生产固定数量的训练样本，</strong>在损失函数中所有用户的权重一样 =&gt; 防止一部分非常活跃的用户主导损失函数值</li>
</ul>
<p><img src="06.png" srcset="/walker_sue/img/loading.gif"></p>
<h3 id="样本和上下文选择中的不对称的共同浏览问题（asymmetric-co-watch）"><a href="#样本和上下文选择中的不对称的共同浏览问题（asymmetric-co-watch）" class="headerlink" title="样本和上下文选择中的不对称的共同浏览问题（asymmetric co-watch）"></a>样本和上下文选择中的<strong>不对称的共同浏览问题</strong>（asymmetric co-watch）</h3><ul>
<li>用户在浏览视频时候，往往都是序列式的，通常会先看一些比较流行的，然后才是观看一些小众的视频。剧集系列通常也是顺序地观看</li>
<li>图(a)是held-out方式，利用上下文信息预估中间的一个视频</li>
<li>图(b)是predicting next watch的方式，则是利用上文信息，预估下一次浏览的视频。</li>
<li>发现预测用户的下一个观看视频的效果要好得多，而不是预测随机推出的视频。</li>
<li>论文发现图(b)的方式在线上A/B test中表现更佳。而实际上，传统的协同过滤类的算法，都是隐含的采用图(a)的held-out方式，忽略了不对称的浏览模式。</li>
<li>方法：从用户的历史视频观看记录中随机拿出来一个作为正样本，然后只用这个视频之前的历史观看记录作为输入（图b）。</li>
</ul>
<p><img src="07.png" srcset="/walker_sue/img/loading.gif"></p>
<h3 id="负采样-Negative-Sampling"><a href="#负采样-Negative-Sampling" class="headerlink" title="负采样 Negative Sampling"></a>负采样 Negative Sampling</h3><ul>
<li>数据处理过程有时候比算法更重要（算法使用可能半天能搞定，但是数据处理/样本处理需要半个月）</li>
<li>采用负采样，也就是随机从全量item中抽取用户没有点击过的item作为label=0的item后，效果明显提升</li>
<li>在当次展现的情况下，虽然用户只点击了click的item，其他item没有点击，但是很多用户在后续浏览的时候未click的item也在其他非列表页的地方进行click，如果将该item标记为label=0，可能是误标记</li>
</ul>
<p><img src="08.png" srcset="/walker_sue/img/loading.gif"></p>
<ul>
<li>论文中提到，推荐列表展示的item极有可能为热门item，虽然该item该用户未点击，但是我们不能降低热门item的权重（通过label=0的方式），实际数据也证明了这一点</li>
<li>推荐列表页中展示的item是算法模型计算出来的 =&gt; 用户最有可能会点击的item</li>
</ul>
<h3 id="不同网络深度和特征的实验"><a href="#不同网络深度和特征的实验" class="headerlink" title="不同网络深度和特征的实验"></a>不同网络深度和特征的实验</h3><ul>
<li>所有的视频和search token都embedded到256维的向量中，开始input层直接全连接到256维的softmax层，依次增加网络深度</li>
</ul>
<p><img src="09.png" srcset="/walker_sue/img/loading.gif"></p>
<ul>
<li>随着网络深度加大，预测准确率在提升，但增加第4层之后，MAP（Mean Average Precision）已经变化不大了</li>
<li>增加了观看历史之外的特征，对预测准确率提升很明显</li>
</ul>
<p><img src="10.png" srcset="/walker_sue/img/loading.gif"></p>
<p>网络深度3层为佳</p>
<h3 id="YouTube的排序阶段"><a href="#YouTube的排序阶段" class="headerlink" title="YouTube的排序阶段"></a>YouTube的排序阶段</h3><ul>
<li>用于精准的预估用户对视频的喜好程度。针对数百个item，需要更多feature来描述item，以及用户与视频（user-item）的关系。比如用户可能很喜欢某个视频，但如果推荐结果采用的“缩略图”选择不当，用户也许不会点击，等等。</li>
<li>Ranking阶段可以将不同来源的候选项进行有效的ensemble（召回阶段的候选集来源很多，没办法直接比较score）</li>
<li>Ranking阶段的模型和召回阶段的基本相似，不同在于Training最后一层是Weighted LR，Serving时激励函数使用的 <img src="https://www.zhihu.com/equation?tex=e%5E%7BWx+b%7D" srcset="/walker_sue/img/loading.gif"></li>
</ul>
<p><img src="11.png" srcset="/walker_sue/img/loading.gif"></p>
<blockquote>
<p>相比召回阶段，引入了更多的feature：<br>当前要计算的video的embedding，<br>用户观看过的最后N个视频embedding的average，<br>用户语言的embedding和当前视频语言的embedding，<br>自上次观看同channel视频的时间，<br>该视频已经被曝光给该用户的次数</p>
</blockquote>
<h3 id="排序阶段的建模（对观看时间）"><a href="#排序阶段的建模（对观看时间）" class="headerlink" title="排序阶段的建模（对观看时间）"></a>排序阶段的建模（对观看时间）</h3><ul>
<li>CTR指标对于视频搜索具有一定的欺骗性，所以论文提出采用期望观看时间作为评估指标</li>
<li>观看时长不是只有0，1两种标签，所以YouTube采用了Weighted Logistic Regression来模拟这个输出</li>
<li>划分样本空间时，正样本为点击，输出值即阅读时长值；负样本为无点击视频，输出值则统一采用1，即采用单位权值，不进行加权</li>
<li>在正常的逻辑回归中，几率odds计算，表示样本为正例概率与负例概率的比例</li>
</ul>
<p><img src="12.png" srcset="/walker_sue/img/loading.gif"></p>
<ul>
<li>引入观看时间时，LR学到的odds表示正例出现概率的和与负样本概率的和的比例</li>
</ul>
<p><img src="13.png" srcset="/walker_sue/img/loading.gif"><br><img src="14.png" srcset="/walker_sue/img/loading.gif"></p>
<ul>
<li>正样本用观看时间赋予权值，负样本赋予单位权值（即不加权）</li>
</ul>
<ul>
<li>每个展示impression的观看时长的期望为</li>
</ul>
<p><img src="15.png" srcset="/walker_sue/img/loading.gif"></p>
<h3 id="排序阶段中的特征工程（Feature-Engineering）"><a href="#排序阶段中的特征工程（Feature-Engineering）" class="headerlink" title="排序阶段中的特征工程（Feature Engineering）"></a>排序阶段中的特征工程（Feature Engineering）</h3><ul>
<li>尽管DNN能够减轻人工特征工程的负担，但是依然需要花费精力将用户及视频数据转化为有效的特征（参考Facebook提出的GBDT+LR模型）</li>
<li>难点在于对用户行为序列建模，并关联视频打分机制</li>
<li>用户对于某Channel的历史行为很重要，比如浏览该频道的次数，最近一次浏览该频道距离现在的时间</li>
<li>把召回阶段的信息传播到Ranking阶段同样能提升效果，比如推荐来源和所在来源的分数</li>
</ul>
<h4 id="排序阶段中的分类特征Embedding（Embedding-Categorical-Features）"><a href="#排序阶段中的分类特征Embedding（Embedding-Categorical-Features）" class="headerlink" title="排序阶段中的分类特征Embedding（Embedding Categorical Features）"></a>排序阶段中的分类特征Embedding（Embedding Categorical Features）</h4><ul>
<li>采用embedding的方式映射稀疏离散特征为密集向量，YouTube为每一个类别特征维度生成一个独立的embedding空间</li>
<li>对于相同域的特征可以共享embedding，好处在于加速迭代，降低内存开销</li>
</ul>
<p><img src="16.png" srcset="/walker_sue/img/loading.gif"></p>
<h4 id="排序阶段中的连续特征归一化（Normalizing-Continuous-Features）"><a href="#排序阶段中的连续特征归一化（Normalizing-Continuous-Features）" class="headerlink" title="排序阶段中的连续特征归一化（Normalizing Continuous Features）"></a>排序阶段中的连续特征归一化（Normalizing Continuous Features）</h4><ul>
<li>排序阶段中的连续特征归一化（Normalizing Continuous Features）：</li>
<li>神经网络对于输入数据的规模和分布非常敏感，而决策树模型（GBDT，RF）对于各个特征的缩放是不受什么影响</li>
<li>连续特征进行归一化对于收敛很重要</li>
<li>设计一种积分函数将特征映射为一个服从[0,1)分布的变量。一个符合f分布的特征x，等价转化成</li>
</ul>
<ul>
<li>除了输入归一化 ，还输入 的平方根和平方，特征的子线性和超线性，会让网络有更强的表达能力（输入连续特征的幂值，被证明是能提高离线精度的）</li>
</ul>
<h3 id="Hideden-Layers实验"><a href="#Hideden-Layers实验" class="headerlink" title="Hideden Layers实验"></a>Hideden Layers实验</h3><ul>
<li>在单个页面上，对展示给用户的正例和负例的这两个impression进行打分，如果对负例打分高于正例打分的话，那么我们认为对于正例预测的观看时间属于错误预测的观看时间</li>
<li>YouTube定义了模型评估指标weighted，per-user loss，即错误预测的观看时间占比总的观看时间的比例。</li>
<li>对每个用户的错误预测loss求和即可获得该用户的loss</li>
<li>实验证明，YouTube采用的Tower塔式模型效果最好，即第一层1024，第二层512，第三层256</li>
</ul>
<p><img src="17.png" srcset="/walker_sue/img/loading.gif"></p>
<h3 id="附：融合推荐模型"><a href="#附：融合推荐模型" class="headerlink" title="附：融合推荐模型"></a>附：融合推荐模型</h3><p>使用卷积神经网络（Convolutional Neural Networks）来学习视频名称的表示。下面会依次介绍文本卷积神经网络以及融合推荐模型。</p>
<ul>
<li>文本卷积神经网络（CNN）<br>  卷积神经网络经常用来处理具有类似网格拓扑结构（grid-like topology）的数据。例如，图像可以视为二维网格的像素点，自然语言可以视为一维的词序列。卷积神经网络可以提取多种局部特征，并对其进行组合抽象得到更高级的特征表示。实验表明，卷积神经网络能高效地对图像及文本问题进行建模处理。<br>  卷积神经网络主要由卷积（convolution）和池化（pooling）操作构成，其应用及组合方式灵活多变，种类繁多。</li>
</ul>
<p><img src="18.png" srcset="/walker_sue/img/loading.gif"></p>
<p>卷积神经网络文本分类模型</p>
<ul>
<li>融合推荐模型概览</li>
</ul>
<p>在融合推荐模型的电影个性化推荐系统中：</p>
<p>（1）首先，使用用户特征和电影特征作为神经网络的输入，其中：</p>
<ul>
<li>用户特征融合了四个属性信息，分别是用户ID、性别、职业和年龄。</li>
<li>电影特征融合了三个属性信息，分别是电影ID、电影类型ID和电影名称。</li>
</ul>
<p>（2）对用户特征，将用户ID映射为维度大小为256的向量表示，输入全连接层，并对其他三个属性也做类似的处理。然后将四个属性的特征表示分别全连接并相加。</p>
<p>（3）对电影特征，将电影ID以类似用户ID的方式进行处理，电影类型ID以向量的形式直接输入全连接层，电影名称用文本卷积神经网络得到其定长向量表示。然后将三个属性的特征表示分别全连接并相加。</p>
<p>（4）得到用户和电影的向量表示后，计算二者的余弦相似度作为个性化推荐系统的打分。最后，用该相似度打分和用户真实打分的差异的平方作为该回归模型的损失函数。</p>
<p>融合推荐模型</p>
<h2 id="再次Summary"><a href="#再次Summary" class="headerlink" title="再次Summary"></a>再次Summary</h2><ul>
<li>召回阶段完成快速筛选（几百万=&gt;几百个），排序阶段完成精排（几百个=&gt;十几个）</li>
<li>基于DNN模型完成召回，排序阶段，自动学习item的embedding特征</li>
<li>DNN的任务是基于用户信息和上下文环境，来学习用户的embedding向量，模拟矩阵分解的过程，DNN最后一层的输出近似作为用户的特征</li>
<li>特征embedding：</li>
</ul>
<blockquote>
<p>将用户观看过的视频id列表做embedding，取embedding向量的平均值，作为watch vector<br>把用户搜索过的视频id列表做embedding，取embedding向量的平均值，作为search vector<br>用户的人口统计学属性做embedding，作为geographic embedding<br>一些非多值类的特征如性别，还有数值类特征直接做DNN的输入<br>一些数值类特征，对其进行变换。如对example age进行平方，平方根操作，作为新的特征</p>
</blockquote>
<ul>
<li>把推荐问题转换成多分类问题，采用Negative Sampling提升模型效果（随机从全量样本中抽取用户没有点击过的item作为label=0，因为推荐列表页中展示的item是算法模型计算出来的 =&gt; 用户最有可能会点击的item）</li>
<li>在召回阶段，采用的近似最近邻查找 =&gt; 提升效率</li>
<li>Youtube的用户对新视频有偏好，引入Example Age（视频上传时间特征） =&gt; 与经验分布更Match</li>
<li>不对称的共同浏览问题，采用predicting next watch的方式，利用上文信息，预估下一次浏览的视频 =&gt; 从用户的历史视频观看记录中随机拿出来一个作为正样本，然后只用这个视频之前的历史观看记录作为输入</li>
<li>对每个用户提取等数量的训练样本 =&gt; 防止一部分非常活跃的用户主导损失函数值</li>
<li>针对某些特征，比如#previous impressions，进行平方和平方根处理，引入3个特征对DNN进行输入 =&gt; 简单有效的特征工程，引入了特征的非线性</li>
<li>在优化目标上，没有采用经典的CTR，或者Play Rate，而是采用了每次曝光预期播放时间作为优化目标</li>
</ul>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/walker_sue/categories/BI/">BI</a>
                    
                      <a class="hover-with-bg" href="/walker_sue/categories/BI/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/">机器学习</a>
                    
                      <a class="hover-with-bg" href="/walker_sue/categories/BI/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%8E%A8%E8%8D%90%E7%AE%97%E6%B3%95/">推荐算法</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/walker_sue/tags/BI/">BI</a>
                    
                      <a class="hover-with-bg" href="/walker_sue/tags/%E6%8E%A8%E8%8D%90%E7%AE%97%E6%B3%95/">推荐算法</a>
                    
                      <a class="hover-with-bg" href="/walker_sue/tags/Wide-Deep/">Wide&Deep</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">本博客所有文章除特别声明外，均采用 <a target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！</p>
              
              
                <div class="post-prevnext row">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/walker_sue/2021/08/07/week22-LSH/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">LSH近似最近邻查找</span>
                        <span class="visible-mobile">Vorheriger</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/walker_sue/2021/07/23/week20-FM/">
                        <span class="hidden-mobile">因子分解机, libFM与基于邻域的协同过滤</span>
                        <span class="visible-mobile">Nächster</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;TOC</p>
  <div id="tocbot"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    
  </main>

  
    <a id="scroll-top-button" href="#" role="button">
      <i class="iconfont icon-arrowup" aria-hidden="true"></i>
    </a>
  

  
    <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">Suchen</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">Stichwort</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
  

  

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
     <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
  </div>
  

  

  
</footer>

<!-- SCRIPTS -->
<script  src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js" ></script>
<script  src="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/js/bootstrap.min.js" ></script>
<script  src="/walker_sue/js/debouncer.js" ></script>
<script  src="/walker_sue/js/main.js" ></script>

<!-- Plugins -->


  
    <script  src="/walker_sue/js/lazyload.js" ></script>
  



  



  <script defer src="https://cdn.staticfile.org/clipboard.js/2.0.6/clipboard.min.js" ></script>
  <script  src="/walker_sue/js/clipboard-use.js" ></script>







  <script  src="https://cdn.staticfile.org/tocbot/4.11.1/tocbot.min.js" ></script>
  <script>
    $(document).ready(function () {
      var boardCtn = $('#board-ctn');
      var boardTop = boardCtn.offset().top;

      tocbot.init({
        tocSelector: '#tocbot',
        contentSelector: '#post-body',
        headingSelector: 'h1,h2,h3,h4,h5,h6',
        linkClass: 'tocbot-link',
        activeLinkClass: 'tocbot-active-link',
        listClass: 'tocbot-list',
        isCollapsedClass: 'tocbot-is-collapsed',
        collapsibleClass: 'tocbot-is-collapsible',
        collapseDepth: 0,
        scrollSmooth: true,
        headingsOffset: -boardTop
      });
      if ($('.toc-list-item').length > 0) {
        $('#toc').css('visibility', 'visible');
      }
    });
  </script>



  <script  src="https://cdn.staticfile.org/typed.js/2.0.11/typed.min.js" ></script>
  <script>
    function typing(id, title){
        var typed = new Typed('#' + id, {
            strings: [
              '  ',
              title + "&nbsp;",
            ],
            cursorChar: "_",
            typeSpeed: 70,
            loop: false,
        });
        typed.stop();
        $(document).ready(function () {
            $(".typed-cursor").addClass("h2");
            typed.start();
        });
    }
    
        typing("subtitle", "CTR预估与Youtube推荐系统")
    
  </script>


  <script  src="https://cdn.staticfile.org/anchor-js/4.2.2/anchor.min.js" ></script>
  <script>
    anchors.options = {
      placement: "right",
      visible: "hover",
      
    };
    var el = "h1,h2,h3,h4,h5,h6".split(",");
    var res = [];
    for (item of el) {
      res.push(".markdown-body > " + item)
    }
    anchors.add(res.join(", "))
  </script>



  <script  src="/walker_sue/js/local-search.js" ></script>
  <script>
    var path = "/walker_sue/local-search.xml";
    var inputArea = document.querySelector("#local-search-input");
    inputArea.onclick = function () {
      searchFunc(path, 'local-search-input', 'local-search-result');
      this.onclick = null
    }
  </script>



  <script  src="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css" />

  <script>
    $('#post img:not(.no-zoom img, img[no-zoom]), img[zoom]').each(
      function () {
        var element = document.createElement('a');
        $(element).attr('data-fancybox', 'images');
        $(element).attr('href', $(this).attr('src'));
        $(this).wrap(element);
      }
    );
  </script>





  

  
    <!-- MathJax -->
    <script>
      MathJax = {
        tex: {
          inlineMath: [['$', '$'], ['\\(', '\\)']]
        },
        options: {
          renderActions: {
            findScript: [10, doc => {
              document.querySelectorAll('script[type^="math/tex"]').forEach(node => {
                const display = !!node.type.match(/; *mode=display/);
                const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display);
                const text = document.createTextNode('');
                node.parentNode.replaceChild(text, node);
                math.start = { node: text, delim: '', n: 0 };
                math.end = { node: text, delim: '', n: 0 };
                doc.math.push(math);
              });
            }, '', false],
            insertedScript: [200, () => {
              document.querySelectorAll('mjx-container').forEach(node => {
                let target = node.parentNode;
                if (target.nodeName.toLowerCase() === 'li') {
                  target.parentNode.classList.add('has-jax');
                }
              });
            }, '', false]
          }
        }
      };
    </script>

    <script async src="https://cdn.staticfile.org/mathjax/3.0.5/es5/tex-svg.js" ></script>

  











</body>
</html>
